package com.settlement.system.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.util.StringUtils;
import com.settlement.system.model.entity.*;
import com.settlement.system.model.query.BillPageQuery;
import com.settlement.system.model.query.OrderPageQuery;
import com.settlement.system.model.vo.IndexDataVo;
import com.settlement.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 有赞账单表 服务实现类
 * </p>
 *
 * @author huangrensen
 * @since 2023-10-23
 */
@Service
@RequiredArgsConstructor
public class IndexServiceImpl implements IndexService {

    private final SysAuditService sysAuditService;
    private final SysRoleService sysRoleService;
    private final SysPlatformService sysPlatformService;
    private final SysOrderService sysOrderService;
    private final SysBillService sysBillService;
    private final RedisTemplate redisTemplate;

    @Override
    public IndexDataVo getData() {
        IndexDataVo vo = new IndexDataVo();
        // 代办事项
        Map<String, Integer> dbsx = new HashMap<>();
        // 所有角色
        List<SysRole> roleList = sysRoleService.list();
        // 所有核销单
        List<SysAudit> auditList = sysAuditService.list();
        // 所有平台
        List<SysPlatform> platformList = sysPlatformService.list();
        // 初始化map
        dbsx.put("代办事项", auditList.size());
        dbsx.put("财务", 0);
        dbsx.put("客服", 0);
        dbsx.put("仓库", 0);
        // 按照角色编码分组
        Map<String, List<SysAudit>> auditMap = auditList.stream().filter(a -> StringUtils.hasText(a.getBelongRole())).collect(Collectors.groupingBy(SysAudit::getBelongRole));
        for (String roleCode : auditMap.keySet()) {
            // 财务
            roleList.stream().filter(role -> role.getName().contains("财务") && role.getCode().equals(roleCode)).findFirst().ifPresent(role -> {
                dbsx.put("财务", dbsx.get("财务") + auditMap.get(roleCode).size());
            });
            // 客服
            roleList.stream().filter(role -> role.getName().contains("客服") && role.getCode().equals(roleCode)).findFirst().ifPresent(role -> {
                dbsx.put("客服", dbsx.get("客服") + auditMap.get(roleCode).size());
            });
            // 仓库
            roleList.stream().filter(role -> role.getName().contains("仓库") && role.getCode().equals(roleCode)).findFirst().ifPresent(role -> {
                dbsx.put("仓库", dbsx.get("仓库") + auditMap.get(roleCode).size());
            });
        }
        // 其他部门
        dbsx.put("其他部门", dbsx.get("代办事项") - dbsx.get("财务") - dbsx.get("客服") - dbsx.get("仓库"));
        vo.setDbsx(dbsx);
        // 期初应收：上月底最后一天待审核核销单收款-退款-保证金退货
        LocalDateTime startDay = LocalDate.now().minusMonths(1).withDayOfMonth(1).minusDays(1).atStartOfDay();
        LocalDateTime endDay = startDay.plusDays(1);
        List<SysAudit> filterAuditList = auditList.stream().filter(audit -> audit.getBusinessDate().isAfter(startDay) && audit.getBusinessDate().isBefore(endDay)).toList();
        // 期初应收：上月底最后一天待审核核销单收款-退款-保证金退货
        Map<String, BigDecimal> qcys = this.handleQCYS(filterAuditList, platformList);
        vo.setQcys(qcys);
        // 应收周期：待审核核销单中最早的业务日期和当前日期的天数差
        Map<String, Long> yszq = this.handleYSZQ(auditList, platformList);
        vo.setYszq(yszq);
        // 应收余额：上月底最后一天待审核核销单收款-退款-保证金退货+按日滚动相加待审核核销单收款-退款-保证金退货
        filterAuditList = auditList.stream().filter(audit -> audit.getBusinessDate().isAfter(endDay)).toList();
        Map<String, BigDecimal> ysye = this.handleQCYS(filterAuditList, platformList);
        for (String key : ysye.keySet()) {
            ysye.put(key, ysye.get(key).add(qcys.get(key)));
        }
        vo.setYsye(ysye);
        // 销售金额：标准订单取销售金额合计
        // 所有订单
        List<SysOrder> allOrders = new ArrayList<>();
        // 所有订单表
//        List<String> orderTables = sysOrderService.getAllOrderTable();
        List<String> orderTables = List.of("sys_order_202402");
        // 订单分页数据
        Page<SysOrder> orderPage;
        int pageNum;
        // 循环查询，每次查500条
        for (String tableName : orderTables) {
            pageNum = 1;
            OrderPageQuery queryParams = new OrderPageQuery();
            queryParams.setPageNum(pageNum);
            queryParams.setPageSize(100000);
            queryParams.setTableName(tableName);
            orderPage = sysOrderService.getAllOrderPage(queryParams);
            while(orderPage.getRecords().size() > 0) {
                allOrders.addAll(orderPage.getRecords());
                pageNum++;
                queryParams.setPageNum(pageNum);
                orderPage = sysOrderService.getAllOrderPage(queryParams);
            }
        }
        Map<String, BigDecimal> xsje = this.handleXSJE(allOrders, platformList);
        vo.setXsje(xsje);
        // 平台费用：标准账单中除了收款金额、退款金额、保证金退款、保证金退款1、信用购分期-保证金退款的账单金额合计
        // 所有账单
        List<SysBill> allBills = new ArrayList<>();
        // 所有账单表
//        List<String> billTables = sysBillService.getAllBillTable();
        List<String> billTables = List.of("sys_bill_202402");;
        // 账单分页数据
        Page<SysBill> billPage;
        // 循环查询，每次查500条
        for (String tableName : billTables) {
            pageNum = 1;
            BillPageQuery queryParams = new BillPageQuery();
            queryParams.setPageNum(pageNum);
            queryParams.setPageSize(100000);
            queryParams.setTableName(tableName);
            billPage = sysBillService.getAllBillPage(queryParams);
            while(billPage.getRecords().size() > 0) {
                allBills.addAll(billPage.getRecords());
                pageNum++;
                queryParams.setPageNum(pageNum);
                billPage = sysBillService.getAllBillPage(queryParams);
            }
        }
        Map<String, BigDecimal> ptfy = this.handlePTFY(allBills, platformList);
        vo.setPtfy(ptfy);
        // 平台利润：销售金额-平台费用-营销费用
        // 初始化map
        Map<String, BigDecimal> ptlr = new HashMap<>();
        for (String key : xsje.keySet()) {
            ptlr.put(key, xsje.get(key).subtract(ptfy.get(key)));
        }
        vo.setPtlr(ptlr);
        // 左边card的数据
        Map<String, Map<String, BigDecimal>> leftCard = this.handleLeftCardData(allOrders, allBills);
        vo.setCardData(leftCard);
        // 缓存数据
        redisTemplate.opsForValue().set(SystemConstants.INDEX_DATA, vo);
        return vo;
    }

    /**
     * 获取期初应收map
     * 上月底最后一天待审核核销单收款-退款-保证金退货
     * @param auditList
     * @param platformList
     * @return
     */
    private Map<String, BigDecimal> handleQCYS(List<SysAudit> auditList, List<SysPlatform> platformList) {
        // 期初应收
        Map<String, BigDecimal> qcys = new HashMap<>();
        // 期初应收总额
        BigDecimal qcysAmount = this.getQCYS(auditList);
        // 初始化map
        qcys.put("合计", qcysAmount);
        qcys.put("天猫", BigDecimal.ZERO);
        qcys.put("京东", BigDecimal.ZERO);
        qcys.put("抖音", BigDecimal.ZERO);
        qcys.put("快手", BigDecimal.ZERO);
        // 按照平台分组
        Map<String, List<SysAudit>> auditMap = auditList.stream().collect(Collectors.groupingBy(SysAudit::getPlatform));
        SysPlatform sysPlatform;
        for (String platformKey : auditMap.keySet()) {
            // 天猫
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("天猫") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                qcys.put("天猫", qcys.get("天猫").add(this.getQCYS(auditMap.get(platformKey))));
            }
            // 京东
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("京东") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                qcys.put("京东", qcys.get("京东").add(this.getQCYS(auditMap.get(platformKey))));
            }
            // 抖音
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("抖音") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                qcys.put("抖音", qcys.get("抖音").add(this.getQCYS(auditMap.get(platformKey))));
            }
            // 快手
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("快手") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                qcys.put("快手", qcys.get("快手").add(this.getQCYS(auditMap.get(platformKey))));
            }
        }
        // 其他平台
        qcys.put("其他平台", qcys.get("合计").subtract(qcys.get("天猫")).subtract(qcys.get("京东")).subtract(qcys.get("抖音")).subtract(qcys.get("快手")));
        return qcys;
    }

    /**
     * 计算期初应收
     * @param auditList
     * @return
     */
    private BigDecimal getQCYS(List<SysAudit> auditList) {
        // 期初应收：收款-退款-保证金退货
        return auditList.stream().map(SysAudit::getReceiveAmount).reduce(BigDecimal.ZERO, BigDecimal::add)
                .add(auditList.stream().map(SysAudit::getRefundAmount).reduce(BigDecimal.ZERO, BigDecimal::add))
                .add(auditList.stream().map(SysAudit::getDepositAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
    }

    /**
     * 计算应收周期
     * 待审核核销单中最早的业务日期和当前日期的天数差
     * @param auditList
     * @param platformList
     * @return
     */
    private Map<String, Long> handleYSZQ(List<SysAudit> auditList, List<SysPlatform> platformList) {
        // 初始化map
        Map<String, Long> yszq = new HashMap<>();
        yszq.put("合计", 0L);
        yszq.put("天猫", 0L);
        yszq.put("京东", 0L);
        yszq.put("抖音", 0L);
        yszq.put("快手", 0L);
        yszq.put("其他平台", 0L);
        // 按照平台分组
        Map<String, List<SysAudit>> auditMap = auditList.stream().collect(Collectors.groupingBy(SysAudit::getPlatform));
        SysPlatform sysPlatform;
        // 获取当前日期
        LocalDate now = LocalDate.now();
        for (String platformKey : auditMap.keySet()) {
            // 天猫
            sysPlatform = platformList.stream().filter(platform -> Objects.nonNull(platform.getReconciliationSystemName()) && platform.getReconciliationSystemName().contains("天猫") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                // 获取最早的业务日期
                auditMap.get(platformKey).stream().min(Comparator.comparing(SysAudit::getBusinessDate)).ifPresent(audit -> {
                    // 计算天数差
                    yszq.put("天猫", ChronoUnit.DAYS.between(audit.getBusinessDate().toLocalDate(), now));
                });
            }
            // 京东
            sysPlatform = platformList.stream().filter(platform -> Objects.nonNull(platform.getReconciliationSystemName()) && platform.getReconciliationSystemName().contains("京东") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                // 获取最早的业务日期
                auditMap.get(platformKey).stream().min(Comparator.comparing(SysAudit::getBusinessDate)).ifPresent(audit -> {
                    // 计算天数差
                    yszq.put("京东", ChronoUnit.DAYS.between(audit.getBusinessDate().toLocalDate(), now));
                });
            }
            // 抖音
            sysPlatform = platformList.stream().filter(platform -> Objects.nonNull(platform.getReconciliationSystemName()) && platform.getReconciliationSystemName().contains("抖音") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                // 获取最早的业务日期
                auditMap.get(platformKey).stream().min(Comparator.comparing(SysAudit::getBusinessDate)).ifPresent(audit -> {
                    // 计算天数差
                    yszq.put("抖音", ChronoUnit.DAYS.between(audit.getBusinessDate().toLocalDate(), now));
                });
            }
            // 快手
            sysPlatform = platformList.stream().filter(platform -> Objects.nonNull(platform.getReconciliationSystemName()) && platform.getReconciliationSystemName().contains("快手") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                // 获取最早的业务日期
                auditMap.get(platformKey).stream().min(Comparator.comparing(SysAudit::getBusinessDate)).ifPresent(audit -> {
                    // 计算天数差
                    yszq.put("快手", ChronoUnit.DAYS.between(audit.getBusinessDate().toLocalDate(), now));
                });
            }
            // 其他平台
            sysPlatform = platformList.stream().filter(platform -> Objects.nonNull(platform.getReconciliationSystemName()) && !platform.getReconciliationSystemName().contains("天猫") && platform.getReconciliationSystemName().contains("京东") && platform.getReconciliationSystemName().contains("抖音") && platform.getReconciliationSystemName().contains("快手")).findFirst().orElse(null);
            if (sysPlatform != null) {
                // 获取最早的业务日期
                auditMap.get(platformKey).stream().min(Comparator.comparing(SysAudit::getBusinessDate)).ifPresent(audit -> {
                    // 计算天数差
                    yszq.put("其他部门", ChronoUnit.DAYS.between(audit.getBusinessDate().toLocalDate(), now));
                });
            }
        }
        return yszq;
    }

    /**
     * 计算销售金额
     * 标准订单取销售金额合计
     * @return
     */
    private Map<String, BigDecimal> handleXSJE(List<SysOrder> orderList, List<SysPlatform> platformList) {
        // 初始化map
        Map<String, BigDecimal> xsje = new HashMap<>();
        xsje.put("合计", orderList.stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        xsje.put("天猫", BigDecimal.ZERO);
        xsje.put("京东", BigDecimal.ZERO);
        xsje.put("抖音", BigDecimal.ZERO);
        xsje.put("快手", BigDecimal.ZERO);
        // 按照平台key分组
        Map<String, List<SysOrder>> orderMap = orderList.stream().collect(Collectors.groupingBy(SysOrder::getPlatform));
        SysPlatform sysPlatform;
        for (String platformKey : orderMap.keySet()) {
            // 天猫
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("天猫") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                xsje.put("天猫", xsje.get("天猫").add(orderMap.get(platformKey).stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
            }
            // 京东
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("京东") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                xsje.put("京东", xsje.get("京东").add(orderMap.get(platformKey).stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
            }
            // 抖音
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("抖音") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                xsje.put("抖音", xsje.get("抖音").add(orderMap.get(platformKey).stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
            }
            // 快手
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("快手") && platform.getPlatformKey().equals(platformKey)).findFirst().orElse(null);
            if (sysPlatform != null) {
                xsje.put("快手", xsje.get("快手").add(orderMap.get(platformKey).stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add)));
            }
        }
        // 其他平台
        xsje.put("其他平台", xsje.get("合计").subtract(xsje.get("天猫")).subtract(xsje.get("京东")).subtract(xsje.get("抖音")).subtract(xsje.get("快手")));
        return xsje;
    }

    /**
     * 计算平台费用
     * 标准账单中除了收款金额、退款金额、保证金退款、保证金退款1、信用购分期-保证金退款的账单金额合计
     * @return
     */
    private Map<String, BigDecimal> handlePTFY(List<SysBill> billList, List<SysPlatform> platformList) {
        // 初始化map
        BigDecimal total = billList.stream().filter(bill -> !bill.getOriginalBillProject().contains("收款金额") &&
                        !bill.getOriginalBillProject().contains("退款金额") &&
                        !bill.getOriginalBillProject().contains("保证金退款") &&
                        !bill.getOriginalBillProject().contains("保证金退款1") &&
                        !bill.getOriginalBillProject().contains("信用购分期-保证金退款")).map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add).abs();
        Map<String, BigDecimal> ptfy = new HashMap<>();
        ptfy.put("合计", total);
        ptfy.put("天猫", BigDecimal.ZERO);
        ptfy.put("京东", BigDecimal.ZERO);
        ptfy.put("抖音", BigDecimal.ZERO);
        ptfy.put("快手", BigDecimal.ZERO);
        List<SysBill> filterBills;
        // 按照对账系统平台编码分组
        Map<String, List<SysBill>> billMap = billList.stream().collect(Collectors.groupingBy(SysBill::getBillSystemPlatformCode));
        SysPlatform sysPlatform;
        for (String billSystemPlatformCode : billMap.keySet()) {
            // 天猫
            sysPlatform = platformList.stream().filter(platform -> platform.getReconciliationSystemName().contains("天猫") && platform.getReconciliationSystemCode().equals(billSystemPlatformCode)).findFirst().orElse(null);
            if (sysPlatform != null) {
                // 过滤数据
                filterBills = billMap.get(billSystemPlatformCode).stream()
                        .filter(bill -> !bill.getOriginalBillProject().contains("收款金额") &&
                                !bill.getOriginalBillProject().contains("退款金额") &&
                                !bill.getOriginalBillProject().contains("保证金退款") &&
                                !bill.getOriginalBillProject().contains("保证金退款1") &&
                                !bill.getOriginalBillProject().contains("信用购分期-保证金退款")).collect(Collectors.toList());
                ptfy.put("天猫", ptfy.get("天猫").add(filterBills.stream().map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add).abs()));
            }
            // 京东
            // 抖音
            // 快手
        }
        // 其他平台
        ptfy.put("其他平台", ptfy.get("合计").subtract(ptfy.get("天猫")).subtract(ptfy.get("京东")).subtract(ptfy.get("抖音")).subtract(ptfy.get("快手")));
        return ptfy;
    }

    /**
     * 计算首页中左边Card的数据
     * @param orderList
     * @return
     */
    private Map<String, Map<String, BigDecimal>> handleLeftCardData(List<SysOrder> orderList, List<SysBill> billList) {
        Map<String, Map<String, BigDecimal>> data = new HashMap<>();
        // 先过滤包含本月的前3个月的订单数据
        LocalDateTime startDate = LocalDateTime.now().minusMonths(2).toLocalDate().withDayOfMonth(1).atStartOfDay();
        LocalDateTime endDate = LocalDateTime.now().plusMonths(1).toLocalDate().withDayOfMonth(1).atStartOfDay();
        List<SysOrder> filterOrders = orderList.stream().filter(o -> o.getBusinessDate().isAfter(startDate) && o.getBusinessDate().isBefore(endDate)).toList();
        List<SysBill> filterBills = billList.stream().filter(b -> b.getBusinessDate().isAfter(startDate) && b.getBusinessDate().isBefore(endDate)).toList();
        // 一个月的订单
        List<SysOrder> monthOrders;
        // 一个月的账单
        List<SysBill> monthBills;
        // 销售净额
        BigDecimal xsje;
        LocalDate now = LocalDateTime.now().toLocalDate();
        for (int i = 0; i < 3; i++) {
            Map<String, BigDecimal> monthData = new HashMap<>();
            LocalDate month = now.minusMonths(i).atStartOfDay().toLocalDate();
            String billMonth = month.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            monthOrders = filterOrders.stream().filter(o -> o.getBusinessDate().toString().startsWith(billMonth)).toList();
            monthBills = filterBills.stream().filter(b -> b.getBusinessDate().toString().startsWith(billMonth)).toList();
            // 销售金额：当月发货金额合计
            monthData.put("销售金额", monthOrders.stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            // 销售净额：当月销售金额合计-退货金额（标准订单）
            xsje = monthOrders.stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add)
                    .subtract(monthOrders.stream().map(SysOrder::getReturnAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            monthData.put("销售净额", xsje);
            // 仅退款金额：账单中的退款金额合计
            monthData.put("仅退款金额", monthBills.stream().filter(b -> b.getOriginalBillProject().contains("退款金额")).map(SysBill::getBillAmount).reduce(BigDecimal.ZERO, BigDecimal::add).abs());
            // 退货金额：订单中的退货金额合计
            monthData.put("退货金额", monthOrders.stream().map(SysOrder::getReturnAmount).reduce(BigDecimal.ZERO, BigDecimal::add).abs());
            data.put("%s月".formatted(month.getMonthValue()), monthData);
        }
        return data;
    }
}
